﻿using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using ReactiveUI;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml.Serialization;

namespace LS.Screening.UI.Common
{
    public class FileConfig<T> : ReactiveObject where T : FileConfig<T>, new()
    {
        private static readonly object lk;

        private static T instance;

        private static readonly List<PropertyInfo> cryptoProperties;

        private static string cryptoKey;

        private static int ivKeyLen;

        protected static string filePath;

        private static JsonSerializerSettings jsonSettings;

        /// <summary>
        /// 单实例
        /// </summary>
        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (lk)
                    {
                        if (instance == null)
                        {
                            CreateInstance();
                        }
                    }
                }

                return instance;
            }
            protected set
            {
                instance = value;
            }
        }

        [SoapIgnore]
        [JsonIgnore]
        protected static string CryptoKey
        {
            get
            {
                if (cryptoKey == string.Empty)
                {
                    string name = typeof(T).Name;
                    List<char> list = new List<char>();
                    string text = name;
                    foreach (char c in text)
                    {
                        if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))
                        {
                            list.Add(c);
                        }
                    }
                    name = string.Join("", list.ToArray());
                    name = name.PadRight(ivKeyLen, '9');
                    int num = name.Length / 2;
                    name = name.Substring(num - ivKeyLen / 2, ivKeyLen);
                    cryptoKey = Convert.ToBase64String(Encoding.UTF8.GetBytes(name));
                }
                return cryptoKey;
            }
        }

        /// <summary>
        /// JSON配置
        /// </summary>
        protected static JsonSerializerSettings JsonSettings
        {
            get
            {
                if (jsonSettings == null)
                {
                    jsonSettings = new JsonSerializerSettings();
                    jsonSettings.Converters.Add(new StringEnumConverter());
                    jsonSettings.DefaultValueHandling = DefaultValueHandling.Include;
                    jsonSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                }
                return jsonSettings;
            }
        }

        /// <summary>
        /// 静态构造
        /// </summary>
        static FileConfig()
        {
            lk = 0;
            cryptoProperties = new List<PropertyInfo>();
            cryptoKey = string.Empty;
            ivKeyLen = 16;
            filePath = null;
            jsonSettings = null;
            filePath = GetConfigFilePath();
            cryptoProperties = GetCryptoProperties(typeof(T));
        }

        /// <summary>
        /// 保存到配置文件
        /// </summary>
        public virtual void Save()
        {
            string text = filePath;
            if (!(instance is AppConfig) && FileConfig<AppConfig>.Instance.RunLocation == RunLocation.Client)
            {
                Dictionary<PropertyInfo, object> dictionary = new Dictionary<PropertyInfo, object>();
                foreach (PropertyInfo cryptoProperty in cryptoProperties)
                {
                    object value = cryptoProperty.GetValue(this);
                    if (value != null && value.ToString() != string.Empty)
                    {
                        dictionary.Add(cryptoProperty, value);
                        value = DEncrypt.AESEncryptStr(value.ToString(), CryptoKey);
                        cryptoProperty.SetValue(this, value);
                    }
                }
                string fileContent = JsonConvert.SerializeObject(this, Formatting.Indented, JsonSettings);
                FileHelper.Write(text, fileContent, FileMode.Truncate, Encoding.UTF8);
                {
                    foreach (KeyValuePair<PropertyInfo, object> item in dictionary)
                    {
                        item.Key.SetValue(this, item.Value);
                    }
                    return;
                }
            }
            string fileContent2 = JsonConvert.SerializeObject(this, Formatting.Indented, JsonSettings);
            FileHelper.Write(text, fileContent2, FileMode.Truncate, Encoding.UTF8);
        }

        /// <summary>
        /// 生成实例时触发
        /// </summary>
        protected virtual void OnCreated()
        {

        }

        /// <summary>
        /// 创建实例
        /// </summary>
        protected static void CreateInstance()
        {
            if (instance != null)
            {
                return;
            }

            if (!File.Exists(filePath))
            {
                instance = new T();
                instance.Save();
            }
            else
            {
                if (instance != null)
                {
                    return;
                }
                string value = FileHelper.Read(filePath, Encoding.UTF8);
                instance = JsonConvert.DeserializeObject<T>(value, JsonSettings);
                bool flag = false;
                if (!(instance is AppConfig) && FileConfig<AppConfig>.instance.RunLocation == RunLocation.Client)
                {
                    foreach (PropertyInfo cryptoProperty in cryptoProperties)
                    {
                        object value2 = cryptoProperty.GetValue(instance);
                        if (value2 != null && value2.ToString() != string.Empty)
                        {
                            try
                            {
                                string value3 = DEncrypt.AESDecryptStr(value2.ToString(), CryptoKey);
                                cryptoProperty.SetValue(instance, value3);
                            }
                            catch
                            {
                                cryptoProperty.SetValue(instance, value2);
                                flag = true;
                            }
                        }
                    }
                }
                if (flag)
                {
                    instance.Save();
                }
            }
            instance.OnCreated();
        }

        /// <summary>
        /// 获取需要加密的熟悉列表
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private static List<PropertyInfo> GetCryptoProperties(Type type)
        {
            List<PropertyInfo> list = new List<PropertyInfo>();
            PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance | BindingFlags.SetProperty);
            properties = properties.Where((PropertyInfo p) => p.PropertyType == typeof(string)).ToArray();
            if (type.GetCustomAttribute<CryptoAttribute>() != null)
            {
                list.AddRange(properties);
            }
            else
            {
                PropertyInfo[] array = properties;
                foreach (PropertyInfo propertyInfo in array)
                {
                    CryptoAttribute customAttribute = propertyInfo.GetCustomAttribute<CryptoAttribute>();
                    if (customAttribute != null)
                    {
                        list.Add(propertyInfo);
                    }
                }
            }
            return list;
        }

        /// <summary>
        /// 获取配置文件全路径
        /// </summary>
        /// <returns></returns>
        protected static string GetConfigFilePath()
        {
            ConfigFileNameAttribute customAttribute = typeof(T).GetCustomAttribute<ConfigFileNameAttribute>();
            if (customAttribute != null)
            {
                string text = customAttribute.FileName;
                if (!text.StartsWith("Config_", StringComparison.OrdinalIgnoreCase))
                {
                    text = "Config_" + text;
                }
                if (!text.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
                {
                    text += ".json";
                }
                return Path.Combine(AppHelper.ConfigDirectory, text);
            }
            return Path.Combine(AppHelper.ConfigDirectory, "Config_" + typeof(T).FullName + ".json");
        }
    }
}
